package com.xlx.openLink.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xlx.openLink.base.BaseMessage;
import com.xlx.openLink.base.BasePage;
import com.xlx.openLink.base.BaseUtils;
import com.xlx.openLink.base.ThreadRunTimeExcption;
import com.xlx.openLink.conf.SystemConfig;
import com.xlx.openLink.dao.AlarmMapper;
import com.xlx.openLink.dao.ConditionsMapper;
import com.xlx.openLink.entity.pojo.Alarm;
import com.xlx.openLink.entity.pojo.Conditions;
import com.xlx.openLink.entity.pojo.Manager;
import com.xlx.openLink.entity.pojo.Speed;
import com.xlx.openLink.enums.*;
import com.xlx.openLink.template.OpenLinkTemplate;
import com.xlx.openLink.template.OpenTemplateCallBack;
import com.xlx.openLink.uitls.AssertUtils;
import com.xlx.openLink.uitls.Commuitls;
import com.xlx.openLink.vo.RequestAlarmList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AlarmService {

    @Autowired
    private AlarmMapper alarmMapper;

    @Autowired
    private OpenLinkTemplate openLinkTemplate;

    @Autowired
    private ConditionsMapper conditionMapper;

    /**
     * 添加告警
     *
     * @param alarm
     * @return
     */

    public BaseMessage addAlarmInfo(Alarm alarm) {
        BaseMessage baseMessage = new BaseMessage();
        openLinkTemplate.execute(new OpenTemplateCallBack() {
            @Override
            public void doCheck() {
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm);
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlPortId());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlDlId());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlPortName());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlDevName());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlMsg());
            }

            @Override
            public void doExecute() {
                addAlarm(alarm);
                baseMessage.buildSuccess(ResultCodeEnum.SUCCESS);
            }
        }, baseMessage, Boolean.TRUE);
        return baseMessage;
    }

    /**
     * 处理告警
     *
     * @param alarm
     * @return
     */
    public BaseMessage optionAlarmInfo(Alarm alarm) {
        BaseMessage baseMessage = new BaseMessage();
        openLinkTemplate.execute(new OpenTemplateCallBack() {
            @Override
            public void doCheck() {
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm);
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getPkGuid());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlStatus());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlDlName());
                AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_EMPTY), alarm.getAlDlId());
            }

            @Override
            public void doExecute() {
                optionAlarm(alarm);
                baseMessage.buildSuccess(ResultCodeEnum.SUCCESS);
            }
        }, baseMessage, Boolean.TRUE);
        return baseMessage;
    }

    private void optionAlarm(Alarm alarm) {
        Alarm al = alarmMapper.selectByPrimaryKey(alarm.getPkGuid());
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.DATA_NOT_EXIST), al);
        alarm.setAlDlDate(new Date());
        alarm.setAlUpdateDate(new Date());
        alarmMapper.updateByPrimaryKeySelective(alarm);
    }

    /**
     * 添加告警
     *
     * @param alarm
     * @return
     */
    private void addAlarm(Alarm alarm) {
        Date nDate = new Date();
        alarm.setAlCreateDate(nDate);
        alarm.setAlDlDate(nDate);
        alarm.setPkGuid(BaseUtils.createGUID());
        alarm.setAlStatus(AlStatusTypeEnum.DCL.getCode());
        alarm.setAlSendStatus(AlSendTypeEnum.UNSENT.getCode());
        alarmMapper.insertSelective(alarm);
    }

    /**
     * 分页查询
     *
     * @param request
     * @return
     */
    public BasePage<Alarm> listByPage(RequestAlarmList request) throws Exception, ThreadRunTimeExcption {
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), request);
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<Alarm> list = alarmMapper.listByPage(request);
        PageInfo pageInfo = new PageInfo(list);
        return new BasePage<Alarm>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal());
    }


    /**
     * 删除
     *
     * @param pkGuid
     * @return
     */
    @Transactional
    public int delAlarm(String pkGuid) throws Exception, ThreadRunTimeExcption {
        AssertUtils.isNotNull(new ThreadRunTimeExcption(ResultCodeEnum.ILLEGAL_PARAM_BLANK), pkGuid);
        return alarmMapper.deleteByPrimaryKey(pkGuid);
    }

    @Transactional
    public int delAll() {

        return alarmMapper.deletAll();
    }

    /**
     * 全部处理
     *
     * @return
     */
    @Transactional
    public int dealAll(Manager manager) {
        List<Alarm> alarms = alarmMapper.selectNoDeal();
        alarms.forEach(e -> {
            e.setAlDlId(manager.getPkGuid());
            e.setAlDlName(manager.getmName());
            e.setAlDlDate(new Date());
            e.setAlStatus("YCL");
        });
        return updateBatch(alarms);
    }

    /**
     * 获取系统告警个数
     *
     * @return
     */
    public int cont() {
        return 1;
    }


    /**
     * 处理告警
     */
    @Transactional
    public void dealAlarm(List<Speed> speeds) {
        List<Alarm> alarms = new ArrayList<>();
        List<Conditions> list = conditionMapper.selectAll();
        HashMap<String, Conditions> portMap = new HashMap<>();
        HashMap<String, Conditions> devMap = new HashMap<>();
        List<Conditions> conditionsList = new ArrayList<>();
        initCondition(list, portMap, devMap, conditionsList);

        for (Speed speed : speeds) {
            Conditions re = selectCondition(portMap, devMap, conditionsList, speed);
            if (re != null) {
                if (speed.getSpInSpeed() > re.getConInMaxRate() && re.getConInMaxRate() != 0) {
                    alarms.add(createAlarm(speed, "设备" + speed.getSpDevName() + "--入网端口--" + speed.getSpPIndex() + "网速超过最大值告警!!!--当前网速:" + Commuitls.formatDouble(speed.getSpInSpeed()) + "M/S"));
                } else if (speed.getSpInSpeed() < re.getConInMinRate() && re.getConInMinRate() != 0) {
                    alarms.add(createAlarm(speed, "设备" + speed.getSpDevName() + "--入网端口--" + speed.getSpPIndex() + "低于最小值告警!!!--当前网速:" + Commuitls.formatDouble(speed.getSpInSpeed()) + "M/S"));
                }
                if (speed.getSpOutSpeed() > re.getConOutMaxRate() && re.getConOutMaxRate() != 0) {
                    alarms.add(createAlarm(speed, "设备" + speed.getSpDevName() + "--出网端口--" + speed.getSpPIndex() + "网速超过最大值告警!!!--当前网速:" + Commuitls.formatDouble(speed.getSpOutSpeed()) + "M/S"));
                } else if (speed.getSpOutSpeed() < re.getConOutMinRate() && re.getConOutMinRate() != 0) {
                    alarms.add(createAlarm(speed, "设备" + speed.getSpDevName() + "--出网端口--" + speed.getSpPIndex() + "低于最小值告警!!!--当前网速:" + Commuitls.formatDouble(speed.getSpOutSpeed()) + "M/S"));
                }
            }
        }

        if (alarms.size() > 0) {
            insertBatch(alarms);
            log.info("产生告警-------------------------");
        }
        log.info("执行告警-----------------------");

    }

    private Alarm createAlarm(Speed speed, String message) {
        //TODO状态没写
        Alarm alarm = new Alarm();
        alarm.setAlMsg(message);
        alarm.setPkGuid(BaseUtils.createGUID());
        alarm.setAlCreateDate(new Date());
        alarm.setAlType(DevTypeEnum.SwitchType.getCode());
        alarm.setAlDevName(speed.getSpDevName());
        alarm.setAlDevId(speed.getDevId());
        alarm.setAlLevel(AlLevel.AL_COMMON.getCode());
        alarm.setAlPortId(speed.getpId());
        alarm.setAlStatus(AlStatusTypeEnum.DCL.getCode());
        alarm.setAlSendStatus(AlSendTypeEnum.UNSENT.getCode());
        return alarm;
    }

    public List<Alarm> selectNoSend() {
        return alarmMapper.selectNoSend();
    }


    @Transactional
    public int updateBatch(List<Alarm> list) {
        int loopCount = list.size() / 100;
        int left = list.size() % 100;
        for (int i = 0; i < loopCount; i++) {
            int fromIndex = i * 100;
            alarmMapper.updateBatch(list.subList(fromIndex, fromIndex + 100));
        }
        if (left > 0) {
            int fromIndex = loopCount * 100;
            alarmMapper.updateBatch(list.subList(fromIndex, fromIndex + left));
        }
        return 1;
    }

    /**
     * 批量更新操作
     *
     * @param list
     * @return
     */
    @Transactional
    public int insertBatch(List<Alarm> list) {
        int loopCount = list.size() / 100;
        int left = list.size() % 100;
        for (int i = 0; i < loopCount; i++) {
            int fromIndex = i * 100;
            alarmMapper.insertBatch(list.subList(fromIndex, fromIndex + 100));
        }
        if (left > 0) {
            int fromIndex = loopCount * 100;
            alarmMapper.insertBatch(list.subList(fromIndex, fromIndex + left));
        }
        return 1;
    }

    private void initCondition(List<Conditions> list,
                               HashMap<String, Conditions> portMap,
                               HashMap<String, Conditions> devMap, List<Conditions> conditionsList) {

        list.forEach(e -> {
            if (e.getConType().equals(ConType.PORT.getCode()) && e.getConPortId() != null) {
                portMap.put(e.getConPortId(), e);
            } else if (e.getConType().equals(ConType.DEV.getCode()) && e.getConDevId() != null) {
                devMap.put(e.getConDevId(), e);
            } else if (e.getConType().equals(ConType.GE.getCode())) {
                conditionsList.add(e);
            }
        });
    }

    private Conditions selectCondition(
            HashMap<String, Conditions> portMap,
            HashMap<String, Conditions> devMap, List<Conditions> conditionsList, Speed s) {

        Conditions conditions = portMap.get(s.getpId());
        if (conditions != null) {
            return conditions;
        } else {
            conditions = devMap.get(s.getDevId());
            if (conditions != null) {
                return conditions;
            } else {
                if (conditionsList.size() > 0) {
                    return conditionsList.get(0);
                } else {
                    return null;
                }
            }
        }
    }
}
